package listeners

import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
)

func RegisterContractAccount(router *gin.Engine) {
	rootGroup := getRootGroup(router)
	cci := rootGroup.Group("/contractaccount")

	cci.POST("/producers", doRegisterProducer)
	cci.GET("/producers", doListProducers)
	cci.PUT("/producers", doUpdateProducer)
	cci.POST("/privileges", doCreatePrivilege)
	cci.GET("/privileges", doListPrivileges)
	//cci.POST("/assignment", doCreateAssignment)

}

func doListProducers(ctx *gin.Context) {
	ctx.JSON(http.StatusOK, producers.Json())
}

func doUpdateProducer(ctx *gin.Context) {
	producer := new(Producer)

	err := ctx.ShouldBind(producer)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, NewErrorMessage(ContractAccount, 1, "doUpdateProducer", fmt.Sprintf("bad parameters: body")))
		return
	}

	if has, _ := producers.Has(*producer); !has {
		ctx.JSON(http.StatusBadRequest, NewErrorMessage(ContractAccount, 2, "doUpdateProducer", fmt.Sprintf("bad parameters: non-xisted producer: %v", producer)))
		return
	}
	producers.Update(*producer)

	ctx.JSON(http.StatusOK, fmt.Sprintf(""))
}

func doRegisterProducer(ctx *gin.Context) {
	producer := new(Producer)

	err := ctx.ShouldBind(producer)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, NewErrorMessage(ContractAccount, 1, "doRegisterProducer", fmt.Sprintf("bad parameters: body")))
		return
	}

	if has, _ := producers.Has(*producer); has {
		ctx.JSON(http.StatusBadRequest, NewErrorMessage(ContractAccount, 2, "doRegisterProducer", fmt.Sprintf("bad parameters: There existed producer")))
		return
	}
	producers.Add(*producer)

	ctx.JSON(http.StatusOK, fmt.Sprintf(""))
}

func doListPrivileges(ctx *gin.Context) {
	ctx.JSON(http.StatusOK, privileges.Json())
}

func doCreatePrivilege(ctx *gin.Context) {
	privilege := new(Privilege)

	err := ctx.ShouldBind(privilege)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, NewErrorMessage(ContractAccount, 1, "doCreatePrivilege", fmt.Sprintf("bad parameters: body")))
		return
	}

	if privileges.Has(*privilege) {
		ctx.JSON(http.StatusBadRequest, NewErrorMessage(ContractAccount, 2, "doCreatePrivilege", fmt.Sprintf("bad parameters: There existed producer")))
		return
	}
	privileges.Add(*privilege)

	ctx.JSON(http.StatusOK, fmt.Sprintf(""))
}

var (
	privileges = make(Privileges, 0)
	producers  = make(Producers, 0)
)

type Privileges []Privilege
type Producers []Producer

func (ps Producers) Has(producer Producer) (bool, int) {
	for index, p := range producers {
		if p.Id == producer.Id {
			return true, index
		} else if p.Name == producer.Name {
			return true, index
		}
	}

	return false, -1
}

func (ps Producers) Update(producer Producer) bool {
	has, i := producers.Has(producer)
	if has {
		producers = append(producers[:i], producers[i+1:]...)
		producers = append(producers, producer)
		has = true
	}

	return has
}

func (ps Producers) Add(producer Producer) bool {
	has, _ := producers.Has(producer)
	if !has {
		producers = append(producers, producer)
		has = true
	}

	return has
}

func (ps Producers) Json() string {
	producersBytes, _ := json.Marshal(producers)

	return string(producersBytes)
}

func (prs Privileges) Has(privilege Privilege) bool {
	for _, p := range privileges {
		if p.Id == privilege.Id {
			return true
		} else if p.Op == privilege.Op {
			return true
		}
	}

	return false
}

func (prs Privileges) Add(privilege Privilege) bool {
	has := false
	if !privileges.Has(privilege) {
		privileges = append(privileges, privilege)
		has = true
	}

	return has
}

func (prs Privileges) Json() string {
	privilegesBytes, _ := json.Marshal(privileges)

	return string(privilegesBytes)
}

type Producer struct {
	Id          string `json:"id"`
	Name        string `json:"name"`
	Initialized bool   `json:"initialized"`

	Privileges []Privilege `json:"privileges"`
}

type Privilege struct {
	Id   string `json:"id"`
	Name string `json:"name"`
	Op   string `json:"op"`
}

//func doCreateAssignment(ctx *gin.Context) {
//
//}
